package com.chzc.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chzc.po.Menu;
import com.chzc.sys.req.MenuREQ;
import com.chzc.sys.mapper.MenuMapper;
import com.chzc.sys.service.IMenuService;
import com.chzc.util.Result;
import com.chzc.util.enums.StatusCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 菜单信息表 服务实现类
 * </p>
 *
 * @author CV大魔王
 * @since 2021-05-24
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements IMenuService {


    @Override
    @Cacheable(value = {"menu"},keyGenerator = "springCacheDefaultKeyGenerator")
    public List<String> findMenuCodeByRoleId(String roleId) {
        return baseMapper.findMenuCodeByRoleId(roleId);
    }

    @Override
    @Cacheable(value = {"menu"},key = "#root.methodName+'_name_'+#req.name")
    public List<Menu> queryList(MenuREQ req) {
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(req.getName())) {
            wrapper.like("name", req.getName());
        }
        // sort升序，update_date降序
        wrapper.orderByAsc("sort").orderByDesc("update_date");
        // 获取所有菜单
        List<Menu> menuList = baseMapper.selectList(wrapper);
        // 封装树状菜单并响应
        return this.buildTree(menuList);
    }


    @Override
    @Caching(evict = {
            @CacheEvict(value = "role",allEntries = true),
            @CacheEvict(value = "user",allEntries = true),
            @CacheEvict(value = "menu",allEntries = true)
    })
    public Result deleteById(String id) {
        //删除当前资源
        baseMapper.deleteById(id);
        // 删除 parent_id = id 的子资源
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getParentId, id);
        baseMapper.delete(wrapper);
        return Result.deleteSuccess();
    }

    /**
     * 先查询跟菜单，然后查询子菜单
     * @param menuList 菜单列表
     * @return 菜单树
     */
    private List<Menu> buildTree(List<Menu> menuList) {
        // 1. 获取根菜单
        List<Menu> rootMenuList = new ArrayList<>();
        for (Menu menu : menuList) {
            // 如果 m.parentId 等于 0 就是根菜单
            if ("0".equals(menu.getParentId())) {
                rootMenuList.add(menu);
            }
        }
        // 2. 根菜单下的子菜单
        for (Menu menu : rootMenuList) {
            childrenMenu(menuList, menu);
        }
        // 3. 返回根菜单，因为根菜单中封装了子菜单
        return rootMenuList;
    }

    /**
     * 根据跟菜单查询子菜单
     * @param menuList 所有的菜单
     * @param menu     父菜单
     * @return 单个菜单树
     */
    private Menu childrenMenu(List<Menu> menuList, Menu menu) {
        // 封装菜单的 parentId = id 子菜单集合
        List<Menu> children = new ArrayList<>();
        // 每次都迭代所有菜单，判断是否为 menu 的子菜单
        for (Menu m : menuList) {
            // 如果 m.parentId 等于 id 则就是它的子菜单
            if (m.getParentId().equals(menu.getId())) {
                // 是子菜单，则递归去找这个菜单的子菜单
                children.add(childrenMenu(menuList, m));
            }
        }
        // 封装 menu 的子菜单
        menu.setChildren(children);
        // 没有子菜单时返回
        return menu;
    }


    @Override
    @Cacheable(value = {"menu"},key = "#root.methodName+'_userId_'+#userId")
    public Result findUserMenuTree(String userId) {
        // 1. 通过用户id查询出拥有的权限（目录、菜单、按钮）
        List<Menu> menuList = baseMapper.findByUserId(userId);
        // 当userId不存在时，menuList 是空的；当存在此用户，但是没有分配权限时会有一条空记录，
        if (CollectionUtils.isEmpty(menuList) || menuList.get(0) == null) {
            // 没有权限
            return new Result(false, StatusCode.COMPETENCE_ERROR.getCode(),StatusCode.COMPETENCE_ERROR.getMessage());
        }
        // 2. 获取权限集合中所有的目录、菜单
        List<Menu> dirMenuList = new ArrayList<>();
        // 封装权限按钮标识符
        List<String> buttonList = new ArrayList<>();
        for (Menu menu : menuList) {
            if (menu.getType().equals(1) || menu.getType().equals(2)) {
                dirMenuList.add(menu);
            } else {
                // 按钮标识符
                buttonList.add(menu.getCode());
            }
        }
        // 3. 封装树状菜单
        List<Menu> menuTreeList = this.buildTree(dirMenuList);
        // 4. 封装响应数据
        Map<String, Object> data = new HashMap<>();
        data.put("menuTreeList", menuTreeList);
        data.put("buttonList", buttonList);
        return Result.querySuccess(data);
    }

    @Override
    @Cacheable(value = {"menu"},key = "#root.methodName+'_userId_'+#userId")
    public List<Menu> findByUserId(String userId) {
        // 通过用户id查询拥有权限
        List<Menu> menuList = baseMapper.findByUserId(userId);
        // 当userId不存在时，menuList 是空的；当存在此用户，但是没有分配权限时会有一条空记录，
        if (CollectionUtils.isEmpty(menuList) || menuList.get(0) == null) {
            // 没有权限
            return null;
        }
        return menuList;
    }

    @Override
    @Caching(evict = {
            @CacheEvict(value = "role",allEntries = true),
            @CacheEvict(value = "user",allEntries = true),
            @CacheEvict(value = "menu",allEntries = true)
    })
    public void saveMenu(Menu menu) {
        menu.setUpdateDate(new Date());
        menu.setCreateDate(new Date());
        baseMapper.insert(menu);
    }

    @Override
    public void updateMenuById(Menu menu) {
        menu.setUpdateDate(new Date());
        baseMapper.updateById(menu);
    }

}
